home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / xmodem.c < prev   
C/C++ Source or Header  |  1994-06-04  |  17KB  |  514 lines

  1. /*
  2.  * A version of Ward Christensen's file transfer protocol for
  3.  * Unix System V or 4.2 bsd.
  4.  *
  5.  *        Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
  6.  *
  7.  * Modified by Sanford Zelkovitz   08/18/86
  8.  * Last modification date = 05/20/87
  9.  * Modified for KA9Q NOS BBS - WA3DSP 2/93
  10.  */
  11.  
  12.  
  13. #include <stdio.h>
  14. #ifndef UNIX
  15. #include <io.h>
  16. #endif
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #include <stdarg.h>
  20. #include "global.h"
  21. #include "dirutil.h"
  22. #include "timer.h" 
  23. #include "socket.h"
  24. #include "mailbox.h"
  25.  
  26. #ifdef TIPMAIL
  27. #ifdef XMODEM
  28.  
  29. #ifdef __cplusplus
  30. extern "C" {
  31. #endif
  32. extern int access __ARGS((const char *, int));
  33. extern int unlink __ARGS((const char *));
  34. #ifdef __cplusplus
  35. }
  36. #endif
  37.  
  38. #define SPEED 2400       /* Serial line Baudrate */
  39.  
  40. #define MAXERRORS 10     /* max number of times to retry */
  41. #define SECSIZE   128    /* CP/M sector, transmission block */
  42. #define CPMEOF    26     /* End Of File (for CP/M) */
  43. #define SOH       1      /* Start Of Header */
  44. #define STX       2      /* Start of 1K block */
  45. #define EOT       4      /* End Of Transmission */
  46. #define ACK       6      /* ACKnowledge */
  47. #define NAK       21     /* Negative AcKnowledge */
  48. #define CAN       24     /* CANcel */
  49. #define BS        8      /* Backspace */ 
  50.  
  51. static int recvfile(char*,struct mbx *m); 
  52. static int sendfile(char*,struct mbx *m);
  53. /*static int truncate(struct mbx *m,char *path,long length);*/
  54. static char getchar_t(int socket);
  55. static void update_crc(unsigned char c, unsigned char *crc1, unsigned char *crc2);
  56. static void error(struct mbx *m);
  57. static void print_text(struct mbx *m,char *fmt, ...);
  58. static void rawmode(struct mbx *);
  59. static void restoremode(struct mbx *);
  60.  
  61. int doxmodem(char mode,char *filename,void *p)
  62. {
  63.         int exit_return=0, oldflush;
  64.         struct mbx *m;
  65.         
  66.         m = (struct mbx *)p;
  67.         oldflush=setflush(m->user,-1);
  68.     
  69.         switch (mode) {
  70.                 case 'r':
  71.                 case 'R':        
  72.                         exit_return=recvfile(filename,m);
  73.                         break;
  74.                 case 's':
  75.                 case 'S':
  76.                         exit_return=sendfile(filename,m);
  77.                         break;
  78.                 default :
  79.                         print_text(m,"Xmodem: Invalid Option\n");
  80.         }
  81.         restoremode(m);
  82.         usputc(m->user,'\n');
  83.         usflush(m->user);
  84.         setflush(m->user,oldflush);
  85.         return(exit_return);
  86. }
  87.  
  88. /* send a file to the remote */
  89. static int
  90. sendfile(char *tfile,struct mbx *m)
  91. {
  92.         FILE *fp;
  93.         unsigned char chr, checksum, block, sector[SECSIZE];
  94.         unsigned char crc1, crc2, mode, errcount, errcount2, two_can;
  95.         int i, nbytes, speed=SPEED;
  96.         long size, min, sec;
  97.         
  98.         if ((size=fsize(tfile))==-1){
  99.                 print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
  100.                 return(1);
  101.         }
  102.  
  103.         if (!(fp = fopen(tfile, READ_BINARY))) {
  104.                 print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
  105.                 return(1);
  106.         }
  107.         
  108.         size=(size/128L)+1L;
  109.         sec = size * 128L * 15L / speed;
  110.         min = sec / 60L;
  111.         sec = sec - min * 60L;
  112.         print_text(m,"\nFile open: %d records\n", size);
  113.         print_text(m,"Send time: %ld min, %ld sec at %d baud\n", min, sec, speed);
  114.         print_text(m,"To cancel: use CTRL-X numerous times\n");
  115.         print_text(m,"Waiting receive ready signal\n");
  116.  
  117.         pause(3000L);
  118.         rawmode(m); 
  119.         errcount = 0;
  120.         mode = 0;
  121.         two_can=0;
  122.         block = 1;
  123.  
  124.         while (errcount < MAXERRORS) {
  125.                 chr = getchar_t(m->user);
  126.                 if (chr == NAK)                        /* checksum mode */
  127.                         break;
  128.                 if (chr == 'C') {                /* CRC mode */
  129.                         mode = 1;
  130.                         break;
  131.                 }
  132.                 if (chr == CAN) {
  133.                         if (two_can)  {
  134.                              pause(3000L);
  135.                              print_text(m,"\nxmodem: Abort request received\n");
  136.                              fclose(fp);
  137.                              return(1);
  138.                          }
  139.                         two_can=1;
  140.                 } else {       
  141.                         two_can=0;
  142.                 }
  143.  
  144.                 errcount++;
  145.         }
  146.         if (errcount >= MAXERRORS) {
  147.                 pause(3000L);
  148.                 print_text(m,"xmodem: Timed out on acknowledge\n");
  149.                 fclose(fp);
  150.                 return(1);
  151.         }
  152.         two_can=0;
  153.         while ((nbytes= fread(sector,1,128, fp))!=0) {
  154.                 if (nbytes < SECSIZE) {              /* fill short sector */
  155.                         for (i=nbytes; i < SECSIZE; i++)
  156.                                 sector[i] = CPMEOF;
  157.                 }
  158.                 errcount = 0;
  159.                 while (errcount < MAXERRORS) {
  160.                         usputc(m->user,SOH);        /* the header */
  161.                         usputc(m->user,block);      /* the block number */
  162.                         chr = ~block;
  163.                         usputc(m->user,chr);        /* it's complement */
  164.                         checksum = 0;
  165.                         crc1 = 0;
  166.                         crc2 = 0;
  167.                         for (i=0; i < SECSIZE; i++) {
  168.                                 usputc(m->user,sector[i]);
  169.                                 if (mode)
  170.                                         update_crc(sector[i],&crc1,&crc2);
  171.                                 else
  172.                                         checksum += sector[i];
  173.                         }
  174.                         if (mode) {
  175.                                 update_crc(0,&crc1,&crc2);
  176.                                 update_crc(0,&crc1,&crc2);
  177.                                 usputc(m->user,crc1);
  178.                                 usputc(m->user,crc2);
  179.                         
  180.                         }
  181.                         else
  182.                                 usputc(m->user,checksum);  
  183.                         
  184.                         usflush(m->user);
  185.                         errcount2=0;
  186. rec_loop:
  187.                         
  188.                         chr = getchar_t(m->user);
  189.                         if (chr == CAN) {
  190.                                 if (two_can)  {
  191.                                         pause(3000L);
  192.                                         print_text(m,"\nxmodem: Abort request received\n");
  193.                                         fclose(fp);
  194.                                         return(1);
  195.                                 }
  196.                                 two_can=1;
  197.                         } else {       
  198.                                 two_can=0;
  199.                         }
  200.                         
  201.                         if (chr == ACK)
  202.                                 break;                /* got it! */
  203.                          /* noise on line? */
  204.                         if (chr != NAK ) {
  205.                                 ++errcount2;
  206.                                 if (errcount2>=MAXERRORS) {
  207.                                           error(m);
  208.                                           fclose(fp);
  209.                                           return 1;
  210.                                 }
  211.                                 goto rec_loop;   
  212.                         }        
  213.                         errcount++;
  214.                 }
  215.                 if (errcount >= MAXERRORS) {
  216.                         error(m);
  217.                         fclose(fp);
  218.                         return(1);
  219.                 }
  220.                 block++;
  221.         }
  222.         errcount = 0;
  223.         while (errcount < MAXERRORS) {
  224.                 usputc(m->user,EOT);
  225.                 usflush(m->user);
  226.                 if (getchar_t(m->user) == ACK)
  227.                         {
  228.                         fclose(fp);
  229.                         pause(6000L);
  230.                         log(m->user,"Xmodem: Download - %s",tfile);
  231.                         print_text(m,"Xmodem: File sent OK\n");
  232.                         return(0);
  233.                         }
  234.                 errcount++;
  235.         }
  236.         fclose(fp);
  237.         pause(3000L);
  238.         error(m);
  239.         return(1);
  240. }
  241.  
  242. /* receive a file from the remote */
  243. static int
  244. recvfile(char *tfile,struct mbx *m)
  245. {
  246.         FILE *fp;
  247.         unsigned char hdr, blk, cblk, tmp, cksum, crc1, crc2;
  248.         unsigned char c1, c2, sum, block, sector[SECSIZE];
  249.         unsigned char first, mode, errcount, two_can;
  250.         int i;
  251.        
  252.         if (!access(tfile, 00)) {
  253.                 print_text(m,"xmodem: File %s already exists\n",tfile);
  254.                 return(1);
  255.         }
  256.  
  257.         if (!(fp = fopen(tfile, WRITE_BINARY))) {
  258.              print_text(m,"xmodem: Can't open '%s' for write\n", tfile);
  259.              return(1);
  260.         }
  261. #ifdef __GNUC__
  262.     c1 = 0;            /* silence warnings */
  263.     c2 = 0;
  264.     cksum = 0;
  265. #endif
  266.         print_text(m,"File open - ready to receive\n");
  267.         print_text(m,"To cancel: use CTRL-X numerous times\n");
  268.         pause(3000L);
  269.         rawmode(m);  
  270.         errcount = 0;
  271.         block = 1;
  272.         first=0;
  273.         two_can=0;
  274.         
  275.         pause(3000L);
  276.         while (errcount < MAXERRORS) {
  277.                 if (errcount < (MAXERRORS / 2)) {
  278.                       usputc(m->user,'C');                /* try CRC mode first */
  279.                       usflush(m->user);
  280.                       mode = 1;
  281.                 }
  282.                 else {
  283.                       usputc(m->user,NAK);                /* then checksum */
  284.                       usflush(m->user);
  285.                       mode = 0;
  286.                 }
  287.                 if ((hdr = getchar_t(m->user)) == SOH) {
  288.                         first=1;
  289.                         break;
  290.                 }
  291.                 if (hdr == CAN) {
  292.                         if (two_can){
  293.                                 pause(3000L);
  294.                                 print_text(m,"\nxmodem: Abort request received\n");
  295.                                 fclose(fp);
  296.                                 unlink(tfile);
  297.                                 return(1);
  298.                         }      
  299.                         two_can=1;
  300.                 } else {       
  301.                         two_can=0;
  302.                 }
  303.                 errcount++;
  304.         }
  305.         if (errcount >= MAXERRORS) {
  306.                 pause(3000L);
  307.                 print_text(m,"\nxmodem: Timed out on acknowledge\n");
  308.                 fclose(fp);
  309.                 unlink(tfile);
  310.                 return(1);
  311.         }
  312.         errcount = 0;
  313.         two_can=0;
  314.         while (errcount < MAXERRORS) {
  315.                 
  316.                 if (first) {
  317.                         hdr=SOH;
  318.                         first=0;
  319.                 } else
  320.                         hdr = getchar_t(m->user);
  321.                 
  322.                 if (hdr == CAN) {
  323.                         if (two_can){
  324.                                 pause(3000L);
  325.                                 print_text(m,"\nxmodem: Abort request received\n");
  326.                                 fclose(fp);
  327.                                 unlink(tfile);
  328.                                 return(1);
  329.                         }      
  330.                         two_can=1;
  331.                         continue;
  332.                 } else {       
  333.                         two_can=0;
  334.                 }
  335.                 
  336.                 if (hdr == EOT)                        /* done! */
  337.                         break;
  338.                 
  339.                 if (hdr != SOH) {             /* read in junk for 6 seconds */
  340.                         alarm(6000L);
  341.                         while(errno != EALARM)
  342.                               rrecvchar(m->user);          
  343.                         alarm(0L);   /* cancel alarm */
  344.                         first=0;
  345.                         goto nak;
  346.                 }
  347.                 blk = getchar_t(m->user);
  348.                 cblk = getchar_t(m->user);
  349.                 crc1 = 0;
  350.                 crc2 = 0;
  351.                 sum = 0;
  352.                 for (i=0; i < SECSIZE; i++) {
  353.                         sector[i] = getchar_t(m->user);
  354.                         if (mode)
  355.                                 update_crc(sector[i],&crc1,&crc2);
  356.                         else
  357.                                 sum += sector[i];
  358.                 }
  359.                 if (mode) {
  360.                         c1 = getchar_t(m->user);
  361.                         c2 = getchar_t(m->user);
  362.                 }
  363.                 else
  364.                         cksum = getchar_t(m->user);
  365.                 if (blk != block && blk != (block - 1))
  366.                         goto nak;
  367.                 tmp = ~blk;
  368.                 if (cblk != tmp)
  369.                         goto nak;
  370.                 if (mode) {
  371.                         update_crc(0,&crc1,&crc2);
  372.                         update_crc(0,&crc1,&crc2);
  373.                         if (c1 != crc1 || c2 != crc2)
  374.                                 goto nak;
  375.                 }
  376.                 else {
  377.                         if (cksum != sum)
  378.                                 goto nak;
  379.                 }
  380.                 if (block == blk) {
  381.                   fflush(fp);
  382.                   if (fwrite(sector, sizeof(sector[0]), SECSIZE, fp)!=SECSIZE){
  383.                         error(m);
  384.                         print_text(m,"         File write error - Partial file deleted\n");
  385.                         fclose(fp);
  386.                         unlink(tfile);
  387.                         return (1);
  388.                   }
  389.                 }
  390.                 block = blk + 1;
  391.                 usputc(m->user,ACK);                        /* got it! */
  392.                 usflush(m->user);
  393.                 errcount = 0;
  394.                 continue;
  395.  
  396.     nak:        usputc(m->user,NAK);                    /* do it over */
  397.                 usflush(m->user);
  398.                 errcount++;
  399.         }
  400.         if (errcount == MAXERRORS) {
  401.                 error(m);
  402.                 fclose(fp);
  403.                 unlink(tfile);
  404.                 return(1);
  405.         }
  406.         usputc(m->user,ACK);
  407.         usflush(m->user);
  408.         pause(3000L);
  409.         fclose(fp);
  410.         log(m->user,"Xmodem: Upload - %s",tfile);
  411.         print_text(m,"Xmodem: File received OK\n");
  412.         return(0);
  413. }        
  414.  
  415. /* exceeded the maximum number of retry's */
  416. static void
  417. error(struct mbx *m)
  418. {
  419.         int i;
  420.         
  421.         for(i=0;i<9;i++) {
  422.                 usputc(m->user,CAN);
  423.         }
  424.         usflush(m->user);
  425.         pause(1000L);
  426.         for(i=0;i<9;i++) {
  427.                 usputc(m->user,BS);
  428.         }
  429.         usflush(m->user);
  430.         pause(3000L);
  431.         print_text(m,"\nxmodem: Exceeded error limit...aborting\n");
  432.         return;
  433. }
  434.  
  435. /* update the CRC bytes */
  436. static void
  437. update_crc(unsigned char c ,unsigned char *crc1 ,unsigned char *crc2)
  438. {
  439.         register int i, temp;
  440.         register unsigned char carry, c_crc1, c_crc2;
  441.         
  442.         for (i=0; i < 8; i++) {
  443.                 temp = c * 2;
  444.                 c = temp;                        /* rotate left */
  445.                 carry = ((temp > 255) ? 1 : 0);
  446.                 temp = *crc2 * 2;
  447.                 *crc2 = temp;
  448.                 *crc2 |= carry;                        /* rotate with carry */
  449.                 c_crc2 = ((temp > 255) ? 1 : 0);
  450.                 temp = *crc1 * 2;
  451.                 *crc1 = temp;
  452.                 *crc1 |= c_crc2;
  453.                 c_crc1 = ((temp > 255) ? 1 : 0);
  454.                 if (c_crc1) {
  455.                         *crc2 ^= 0x21;
  456.                         *crc1 ^= 0x10;
  457.                 }
  458.         }
  459.         return;
  460. }
  461.  
  462. /* getchar with a 5 sec time out */
  463. static char
  464. getchar_t(int s)
  465. {
  466.         char c;
  467.         /* only have 5 sec... */ 
  468.         alarm(5000L);
  469.         /* Wait for something to happen */
  470.         c=rrecvchar(s); 
  471.         alarm(0L);
  472.         return(c);
  473. }
  474.                           
  475. /* put the stdin/stdout in the "raw" mode */
  476. static void 
  477. rawmode(struct mbx *m)
  478. {
  479.         seteol(m->user,0);
  480.         seteol(m->tip->s,0);
  481.         sockmode(m->tip->s,SOCK_BINARY);
  482.         sockmode(m->user,SOCK_BINARY);
  483.         m->tip->raw=1;
  484. }
  485.  
  486. static void 
  487. restoremode(struct mbx *m)
  488. {
  489.         while(socklen(m->user,0) != 0)
  490.            recv_mbuf(m->user,NULL,0,NULLCHAR,0); 
  491.         seteol(m->user,"\n");
  492.         seteol(m->tip->s,"\n");
  493.         sockmode(m->user,SOCK_ASCII);
  494.         sockmode(m->tip->s,SOCK_ASCII);
  495.         m->tip->raw=0;
  496. }
  497.  
  498. void
  499. print_text(struct mbx *m,char *fmt, ...)
  500. {
  501.         va_list ap;
  502.         char buf[80];
  503.  
  504.         restoremode(m);       
  505.         va_start(ap,fmt);
  506.         vsprintf(buf,fmt,ap);
  507.         va_end(ap);
  508.         usprintf(m->user,buf);
  509.         usflush(m->user);
  510. }        
  511.  
  512. #endif
  513. #endif
  514.